package cn.qdhlm.collectservice.core.component.analyse;


import cn.qdhlm.collectservice.common.Constant;
import cn.qdhlm.collectservice.common.helper.ProtocolHelper;
import cn.qdhlm.collectservice.common.util.CodeUtil;
import cn.qdhlm.collectservice.common.util.ComUtil;
import cn.qdhlm.collectservice.common.util.JsonUtil;
import cn.qdhlm.collectservice.core.component.Checker;
import cn.qdhlm.collectservice.model.rocketmq.TerminalData;
import cn.qdhlm.collectservice.service.UtilityService;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.rocketmq.client.producer.SendResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Name: AnyAfn0a
 * @Description: 1类数据（AFN=0AH）
 * @Author: jiangcs
 */
@Log4j2
@Component
public class AnyAfn0a {

    @Autowired
    private UtilityService utilityService;

    public boolean execute(int fn, ByteBuf byteBuf, TerminalData terminalData) {
        boolean executeFlag = false;

        int networkOperator, version, signal, networkTime, packageCount, collectStatus;
        StringBuilder sbIccid, sbImei, sbModuleModel, sbTerminalModel;
        double voltage;
        String year, month, day, hour, minute, second, moduleTime, terminalState = "", collectTime;
        Map<String, Object> varMap;
        switch (fn) {
            // F1：透传实时数据
            case 1:
                // 程序版本
                version = byteBuf.readByte();
                // iccid
                sbIccid = new StringBuilder();
                for (int i = 0; i < Constant.BYTE_LENGTH_ICCID; i++) {
                    String asciiStr = CodeUtil.byteToHexString(byteBuf.readByte());
                    if (Constant.SYMBOL_00.equals(asciiStr)) {
                        // 跳过剩余字节
                        byteBuf.skipBytes(Constant.BYTE_LENGTH_ICCID - i - 1);
                        break;
                    }
                    sbIccid.append(CodeUtil.hexStringToAsciiString(asciiStr));
                }
                // 模组时间
                second = CodeUtil.byteToHexString(byteBuf.readByte());
                minute = CodeUtil.byteToHexString(byteBuf.readByte());
                hour = CodeUtil.byteToHexString(byteBuf.readByte());
                day = CodeUtil.byteToHexString(byteBuf.readByte());
                month = CodeUtil.byteToHexString(byteBuf.readByte());
                year = "20" + CodeUtil.byteToHexString(byteBuf.readByte());
                moduleTime = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
                // 信号
                signal = byteBuf.readByte();
                // 电压
                voltage = ComUtil.formatScale(byteBuf.readShortLE() * 0.01, 2);
                // 采集时间
                second = CodeUtil.byteToHexString(byteBuf.readByte());
                minute = CodeUtil.byteToHexString(byteBuf.readByte());
                hour = CodeUtil.byteToHexString(byteBuf.readByte());
                day = CodeUtil.byteToHexString(byteBuf.readByte());
                month = CodeUtil.byteToHexString(byteBuf.readByte());
                year = "20" + CodeUtil.byteToHexString(byteBuf.readByte());
                collectTime = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
                // 数据包数量
                packageCount = byteBuf.readByte();

                log.info("execute: version[{}], iccid[{}], moduleTime[{}], signal[{}], voltage[{}], collectTime[{}], packageCount[{}]",
                        version, sbIccid, moduleTime, signal, voltage, collectTime, packageCount);

                // 变量以及变量值
                varMap = new LinkedHashMap<>();

                // 采集状态：1-失败
                collectStatus = 1;

                if (packageCount <= 0) {
                    log.error("execute: packageCount <= 0");
                } else {
                    // 处理数据
                    for (int i = 0; i < packageCount; i++) {
                        collectStatus &= processTransparentData(byteBuf, varMap, terminalData);
                    }
                    if (collectStatus == 0) {
                        // 终端状态
//                        terminalState = protocolStateMapper.matchTerminalState(ComUtil.safeInt(varMap.get("02")), protocolCode.getProtocolCode());
                    }
                }

                // 数据存储至mongodb
                executeFlag = utilityService.sendTerminalData(terminalData, varMap, collectStatus, ComUtil.safeString(terminalState), collectTime, sbIccid.toString(), version, signal, voltage, moduleTime);
                break;
            // F2：NB温湿度记录仪实时数据
            case 2:
                // 产品型号
                sbTerminalModel = new StringBuilder();
                for (int i = 0; i < Constant.BYTE_LENGTH_TERMINAL_MODEL; i++) {
                    String asciiStr = CodeUtil.byteToHexString(byteBuf.readByte());
                    if (Constant.SYMBOL_00.equals(asciiStr)) {
                        // 跳过剩余字节
                        byteBuf.skipBytes(Constant.BYTE_LENGTH_TERMINAL_MODEL - i - 1);
                        break;
                    }
                    sbTerminalModel.append(CodeUtil.hexStringToAsciiString(asciiStr));
                }
                // 网络运营商：0：NB移动，1：NB电信
                networkOperator = byteBuf.readByte();
                // 程序版本
                version = byteBuf.readByte();
                // iccid
                sbIccid = new StringBuilder();
                for (int i = 0; i < Constant.BYTE_LENGTH_ICCID; i++) {
                    String asciiStr = CodeUtil.byteToHexString(byteBuf.readByte());
                    if (Constant.SYMBOL_00.equals(asciiStr)) {
                        // 跳过剩余字节
                        byteBuf.skipBytes(Constant.BYTE_LENGTH_ICCID - i - 1);
                        break;
                    }
                    sbIccid.append(CodeUtil.hexStringToAsciiString(asciiStr));
                }
                // 模组时间
                second = CodeUtil.byteToHexString(byteBuf.readByte());
                minute = CodeUtil.byteToHexString(byteBuf.readByte());
                hour = CodeUtil.byteToHexString(byteBuf.readByte());
                day = CodeUtil.byteToHexString(byteBuf.readByte());
                month = CodeUtil.byteToHexString(byteBuf.readByte());
                year = "20" + CodeUtil.byteToHexString(byteBuf.readByte());
                moduleTime = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
                // 信号
                signal = byteBuf.readByte();
                // 电压
                voltage = ComUtil.formatScale(byteBuf.readShortLE() * 0.01, 2);
                // 联网时长
                networkTime = byteBuf.readShortLE();
                // 预留
                byteBuf.skipBytes(4);
                // 报警故障位
                // DB0：0:无移动报警，1：移动报警
                // DB1：0：温湿度传感器无故障，1：温湿度传感器故障
                // DB2：0：电池正常，1：电池欠压
                short stateValue = byteBuf.readShortLE();
                // 数据包数量
                packageCount = byteBuf.readByte();

                log.info("execute: terminalModel[{}], networkOperator[{}], version[{}], iccid[{}], moduleTime[{}], signal[{}], voltage[{}], networkTime[{}], stateValue[{}], packageCount[{}]",
                        sbTerminalModel, networkOperator, version, sbIccid, moduleTime, signal, voltage, networkTime, stateValue, packageCount);

                if (packageCount <= 0) {
                    log.error("execute: packageCount <= 0");
                } else {
                    // 处理数据
                    for (int i = 0; i < packageCount; i++) {
                        // 变量以及变量值
                        varMap = new LinkedHashMap<>();
                        varMap.put("02", stateValue);
                        varMap.put("12", networkTime);

                        collectStatus = processNTR200Data(byteBuf, varMap);

                        if (collectStatus == 0) {
                            // 终端状态
//                            terminalState = protocolStateMapper.matchTerminalState(ComUtil.safeInt(varMap.get("02")), protocolCode.getProtocolCode());
                        }

                        // 数据存储至mongodb
                        utilityService.sendTerminalData(terminalData, varMap, collectStatus, ComUtil.safeString(terminalState), ComUtil.safeString(varMap.get("15")), sbIccid.toString(), version, signal, voltage, moduleTime);
                    }

                    executeFlag = true;
                }
                break;
            // F3：NBT200-AC实时数据
            case 3:
                // 产品型号
                sbTerminalModel = new StringBuilder();
                for (int i = 0; i < Constant.BYTE_LENGTH_TERMINAL_MODEL; i++) {
                    String asciiStr = CodeUtil.byteToHexString(byteBuf.readByte());
                    if (Constant.SYMBOL_00.equals(asciiStr)) {
                        // 跳过剩余字节
                        byteBuf.skipBytes(Constant.BYTE_LENGTH_TERMINAL_MODEL - i - 1);
                        break;
                    }
                    sbTerminalModel.append(CodeUtil.hexStringToAsciiString(asciiStr));
                }
                // 网络运营商：0：NB移动，1：NB电信
                networkOperator = byteBuf.readByte();
                // 程序版本
                version = byteBuf.readByte();
                // iccid
                sbIccid = new StringBuilder();
                for (int i = 0; i < Constant.BYTE_LENGTH_ICCID; i++) {
                    String asciiStr = CodeUtil.byteToHexString(byteBuf.readByte());
                    if (Constant.SYMBOL_00.equals(asciiStr)) {
                        // 跳过剩余字节
                        byteBuf.skipBytes(Constant.BYTE_LENGTH_ICCID - i - 1);
                        break;
                    }
                    sbIccid.append(CodeUtil.hexStringToAsciiString(asciiStr));
                }
                // 模组时间
                second = CodeUtil.byteToHexString(byteBuf.readByte());
                minute = CodeUtil.byteToHexString(byteBuf.readByte());
                hour = CodeUtil.byteToHexString(byteBuf.readByte());
                day = CodeUtil.byteToHexString(byteBuf.readByte());
                month = CodeUtil.byteToHexString(byteBuf.readByte());
                year = "20" + CodeUtil.byteToHexString(byteBuf.readByte());
                moduleTime = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
                // 信号
                signal = byteBuf.readByte();
                // 电压
                voltage = ComUtil.formatScale(byteBuf.readShortLE() * 0.01, 2);
                // 联网时长
                networkTime = byteBuf.readShortLE();
                // 预留
                byteBuf.skipBytes(4);
                // 数据包数量
                packageCount = byteBuf.readByte();

                log.info("execute: terminalModel[{}], networkOperator[{}], version[{}], iccid[{}], moduleTime[{}], signal[{}], voltage[{}], networkTime[{}], packageCount[{}]",
                        sbTerminalModel, networkOperator, version, sbIccid, moduleTime, signal, voltage, networkTime, packageCount);

                if (packageCount <= 0) {
                    log.error("execute: packageCount <= 0");
                } else {
                    // 处理数据
                    for (int i = 0; i < packageCount; i++) {
                        // 变量以及变量值
                        varMap = new LinkedHashMap<>();
                        varMap.put("12", networkTime);

                        collectStatus = processNBT200ACData(byteBuf, varMap);

                        if (collectStatus == 0) {
                            // 终端状态
//                            terminalState = protocolStateMapper.matchTerminalState(ComUtil.safeInt(varMap.get("02")), protocolCode.getProtocolCode());
                        }

                        // 数据存储至mongodb
                        utilityService.sendTerminalData(terminalData, varMap, collectStatus, ComUtil.safeString(terminalState), ComUtil.safeString(varMap.get("15")), sbIccid.toString(), version, signal, voltage, moduleTime);
                    }

                    executeFlag = true;
                }
                break;
            // F4：带实时参数实时数据
            case 4:
                // 程序版本
                version = byteBuf.readByte();
                // iccid
                sbIccid = new StringBuilder();
                for (int i = 0; i < Constant.BYTE_LENGTH_ICCID; i++) {
                    String asciiStr = CodeUtil.byteToHexString(byteBuf.readByte());
                    if (Constant.SYMBOL_00.equals(asciiStr)) {
                        // 跳过剩余字节
                        byteBuf.skipBytes(Constant.BYTE_LENGTH_ICCID - i - 1);
                        break;
                    }
                    sbIccid.append(CodeUtil.hexStringToAsciiString(asciiStr));
                }
                // imei
                sbImei = new StringBuilder();
                for (int i = 0; i < Constant.BYTE_LENGTH_IMEI; i++) {
                    String asciiStr = CodeUtil.byteToHexString(byteBuf.readByte());
                    if (Constant.SYMBOL_00.equals(asciiStr)) {
                        // 跳过剩余字节
                        byteBuf.skipBytes(Constant.BYTE_LENGTH_IMEI - i - 1);
                        break;
                    }
                    sbImei.append(CodeUtil.hexStringToAsciiString(asciiStr));
                }
                // 模组型号
                sbModuleModel = new StringBuilder();
                for (int i = 0; i < Constant.BYTE_LENGTH_MODULE_MODEL; i++) {
                    String asciiStr = CodeUtil.byteToHexString(byteBuf.readByte());
                    if (Constant.SYMBOL_00.equals(asciiStr)) {
                        // 跳过剩余字节
                        byteBuf.skipBytes(Constant.BYTE_LENGTH_MODULE_MODEL - i - 1);
                        break;
                    }
                    sbModuleModel.append(CodeUtil.hexStringToAsciiString(asciiStr));
                }
                // 模组时间
                second = CodeUtil.byteToHexString(byteBuf.readByte());
                minute = CodeUtil.byteToHexString(byteBuf.readByte());
                hour = CodeUtil.byteToHexString(byteBuf.readByte());
                day = CodeUtil.byteToHexString(byteBuf.readByte());
                month = CodeUtil.byteToHexString(byteBuf.readByte());
                year = "20" + CodeUtil.byteToHexString(byteBuf.readByte());
                moduleTime = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
                // 信号
                signal = byteBuf.readByte();
                // 电压
                voltage = ComUtil.formatScale(byteBuf.readShortLE() * 0.01, 2);
                // 运行参数数据长度
                int configParamLength = byteBuf.readShortLE();
                if (configParamLength > 0) {
                    // 运行参数数据
                    processTerminalNBConfigParam(terminalData.getTerminalId(), terminalData.getProtocolCode(), byteBuf.copy(byteBuf.readerIndex(), configParamLength));

                    byteBuf.skipBytes(configParamLength);
                }
                // 采集时间
                second = CodeUtil.byteToHexString(byteBuf.readByte());
                minute = CodeUtil.byteToHexString(byteBuf.readByte());
                hour = CodeUtil.byteToHexString(byteBuf.readByte());
                day = CodeUtil.byteToHexString(byteBuf.readByte());
                month = CodeUtil.byteToHexString(byteBuf.readByte());
                year = "20" + CodeUtil.byteToHexString(byteBuf.readByte());
                collectTime = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
                // 数据包数量
                packageCount = byteBuf.readByte();

                log.info("execute fn[{}]: version[{}], iccid[{}], imei[{}], moduleModel[{}], moduleTime[{}], signal[{}], voltage[{}], configParamLength[{}], collectTime[{}], packageCount[{}]",
                        fn, version, sbIccid, sbImei, sbModuleModel, moduleTime, signal, voltage, configParamLength, collectTime, packageCount);

                // 变量以及变量值
                varMap = new LinkedHashMap<>();

                // 采集状态：1-失败
                collectStatus = 1;

                if (packageCount <= 0) {
                    log.error("execute fn[{}]: packageCount <= 0", fn);
                } else {
                    // 处理数据
                    for (int i = 0; i < packageCount; i++) {
                        collectStatus &= processTransparentData(byteBuf, varMap, terminalData);
                    }
                    if (collectStatus == 0) {
                        // 终端状态
//                        terminalState = protocolStateMapper.matchTerminalState(ComUtil.safeInt(varMap.get("02")), protocolCode.getProtocolCode());
                    }
                }

                // 数据存储至mongodb
                executeFlag = utilityService.sendTerminalData(terminalData, varMap, collectStatus, ComUtil.safeString(terminalState), collectTime, sbIccid.toString(), version, signal, voltage, moduleTime);
                break;
            default:
                log.error("execute: fn[{}] match fail", fn);
        }

        return executeFlag;
    }

    /**
     * 处理 透传数据包
     *
     * @param byteBuf
     * @param varMap

     * @return
     */
    private int processTransparentData(ByteBuf byteBuf, Map<String, Object> varMap, TerminalData terminalData) {
        // 采集状态
        int collectStatus = 1;

        // 包序号
        int packageNum = byteBuf.readByte();
        // 包长度
        int packageLength = byteBuf.readShortLE();
        if (packageLength > 0) {
            // 截取 透传数据包
            ByteBuf byteBufData = byteBuf.copy(byteBuf.readerIndex(), packageLength);

            log.info("process transparentData: packageNum[{}], packageLength[{}], byteBufData[{}]", packageNum, packageLength, ByteBufUtil.hexDump(byteBufData));

            try {
                boolean checkFlag = Checker.checkTransparent(byteBufData);
                if (checkFlag) {
                    int index = 0;

                    // 跳过：起始字符
                    index++;

                    // 跳过：仪表类型：46
                    index++;

                    // 地址域：终端地址
                    StringBuilder macAddr = new StringBuilder();
                    for (int i = Constant.BYTE_LENGTH_MAC_ADDR - 1; i >= 0; i--) {
                        macAddr.append(CodeUtil.byteToHexString(byteBufData.getByte(index + i)));
                    }
                    index += 4;

                    // 地址域：厂家代码
                    StringBuilder factory = new StringBuilder();
                    for (int i = 0; i < Constant.BYTE_LENGTH_FACTORY; i++) {
                        factory.append(CodeUtil.byteToHexString(byteBufData.getByte(index + i)));
                    }
                    index += 3;

                    // 控制码
                    index++;

                    // 数据长度
                    int dataLength = byteBufData.getByte(index);

                    log.info("process transparentData: macAddr[{}], factory[{}], dataLength[{}]", macAddr.toString(), factory.toString(), dataLength);

                    // 变量数据
                    processVarData(byteBufData, varMap, packageNum, terminalData);

                    collectStatus = 0;
                }
            } catch (Exception e) {
                log.error("process transparentData: processVarData exception ", e);
            }
        } else {
            log.error("process transparentData: packageLength <= 0");
        }

        // 跳过已解析字节 + cs 16
        byteBuf.skipBytes(packageLength + 2);

        return collectStatus;
    }

    private void processVarData(ByteBuf byteBuf, Map<String, Object> varMap, int packageNum, TerminalData terminalData) throws Exception {
        // 协议：命令参数
        String protocolCode = terminalData.getProtocolCode();
        Map<String, Object> paramCommandMap = ProtocolHelper.getParameterMap(protocolCode, (packageNum + 1) + "_command");
        // 变量个数
        int varNum;
        if (paramCommandMap == null) {
            throw new RuntimeException("process paramCommandMap is null");
        }
        varNum = ComUtil.safeInt(paramCommandMap.get("variablenum1"));
        if (varNum <= 0) {
            throw new RuntimeException("process varData.varNum[" + varNum + "] <= 0");
        }

        Map<String, Object> paramVarMap;
        String section, varType;
        int dataStart, dataEnd, dataOrder, dataType, dataPoint, dataUnit;
        for (int i = 0; i < varNum; i++) {
            section = (packageNum + 1) + "_var" + (i + 1);
            paramVarMap = ProtocolHelper.getParameterMap(protocolCode, section);
            if (paramVarMap == null) {
                throw new RuntimeException("process varData.paramVarMap is empty: protocolCode[" + protocolCode + "], section[" + section + "]");
            }

            varType = ComUtil.fillZeroLeft(Integer.parseInt(ComUtil.safeString(paramVarMap.get("vartype")), 16), 2);
            dataStart = ComUtil.safeInt(paramVarMap.get("datastart"));
            dataEnd = ComUtil.safeInt(paramVarMap.get("dataend"));
            // 0-正序；1-逆序
            dataOrder = ComUtil.safeInt(paramVarMap.get("dataorder"));
            // 0-BCD；1-hex int；2-hex float
            dataType = ComUtil.safeInt(paramVarMap.get("datatype"));
            dataPoint = ComUtil.safeInt(paramVarMap.get("datapoint"));
            dataUnit = ComUtil.safeInt(paramVarMap.get("dataunit"));

            log.info("process varData: varType[{}],dataStart[{}],dataEnd[{}],dataOrder[{}],dataType[{}],dataPoint[{}],dataUnit[{}]", varType, dataStart, dataEnd, dataOrder, dataType, dataPoint, dataUnit);

            // 采集时间：v15、v20
            if ("15".equals(varType) || "20".equals(varType)) {
                String v15 = null;
                // 正序: 20191230123050
                if (dataOrder == 0) {
                    v15 = CodeUtil.byteToHexString(byteBuf.getByte(dataStart)) + CodeUtil.byteToHexString(byteBuf.getByte(dataStart + 1)) + "-" + CodeUtil.byteToHexString(byteBuf.getByte(dataStart + 2)) + "-" + CodeUtil.byteToHexString(byteBuf.getByte(dataStart + 3)) + " " +
                            CodeUtil.byteToHexString(byteBuf.getByte(dataStart + 4)) + ":" + CodeUtil.byteToHexString(byteBuf.getByte(dataStart + 5)) + ":" + CodeUtil.byteToHexString(byteBuf.getByte(dataStart + 6));
                }
                // 逆序: 50301230121920
                else if (dataOrder == 1) {
                    v15 = CodeUtil.byteToHexString(byteBuf.getByte(dataEnd)) + CodeUtil.byteToHexString(byteBuf.getByte(dataEnd - 1)) + "-" + CodeUtil.byteToHexString(byteBuf.getByte(dataEnd - 2)) + "-" + CodeUtil.byteToHexString(byteBuf.getByte(dataEnd - 3)) + " " +
                            CodeUtil.byteToHexString(byteBuf.getByte(dataEnd - 4)) + ":" + CodeUtil.byteToHexString(byteBuf.getByte(dataEnd - 5)) + ":" + CodeUtil.byteToHexString(byteBuf.getByte(dataEnd - 6));
                }
                varMap.put(varType, v15);
            }
            // 其他 按照 dataType 处理
            else {
                switch (dataType) {
                    // BCD
                    case 0:
                        StringBuilder varData = new StringBuilder();
                        // 正序
                        if (dataOrder == 0) {
                            for (int m = dataStart; m <= dataEnd; m++) {
                                varData.append(CodeUtil.byteToHexString(byteBuf.getByte(m)));
                            }
                        }
                        // 逆序
                        else if (dataOrder == 1) {
                            for (int n = dataEnd; n >= dataStart; n--) {
                                varData.append(CodeUtil.byteToHexString(byteBuf.getByte(n)));
                            }
                        }

                        // 转换小数
                        double bcdValue;
                        if (dataPoint == 0) {
                            bcdValue = Double.parseDouble(varData.toString());
                        } else {
                            bcdValue = ComUtil.doubleConvert(Integer.parseInt(varData.toString()), 0.1, dataPoint);
                        }

                        // 单位转换
                        if (dataUnit != 0) {
                            bcdValue = ComUtil.unitConvert(bcdValue, byteBuf.getByte(dataUnit), protocolCode);
                        }

                        varMap.put(varType, ComUtil.formatScale(bcdValue, 3));
                        break;
                    // hex int
                    case 1:
                        int byteCount = dataEnd - dataStart + 1;
                        switch (byteCount) {
                            // byte
                            case 1:
                                byte byteValue = byteBuf.getByte(dataStart);
                                if (dataPoint == 0) {
                                    varMap.put(varType, byteValue);
                                } else {
                                    varMap.put(varType, ComUtil.doubleConvert(byteValue, 0.1, dataPoint));
                                }
                                break;
                            // short
                            case 2:
                                short shortValue = dataOrder == 0 ? byteBuf.getShort(dataStart) : byteBuf.getShortLE(dataStart);
                                if (dataPoint == 0) {
                                    varMap.put(varType, shortValue);
                                } else {
                                    varMap.put(varType, ComUtil.doubleConvert(shortValue, 0.1, dataPoint));
                                }
                                break;
                            // medium
                            case 3:
                                int mediumValue = dataOrder == 0 ? byteBuf.getMedium(dataStart) : byteBuf.getMediumLE(dataStart);
                                if (dataPoint == 0) {
                                    varMap.put(varType, mediumValue);
                                } else {
                                    varMap.put(varType, ComUtil.doubleConvert(mediumValue, 0.1, dataPoint));
                                }
                                break;
                            // int
                            case 4:
                                int intValue = dataOrder == 0 ? byteBuf.getInt(dataStart) : byteBuf.getIntLE(dataStart);
                                if (dataPoint == 0) {
                                    varMap.put(varType, intValue);
                                } else {
                                    varMap.put(varType, ComUtil.doubleConvert(intValue, 0.1, dataPoint));
                                }
                                break;
                            default:
                                log.error("process varData: dataType[{}], byteCount[{}] match fail", dataType, byteCount);
                        }
                        break;
                    // hex float
                    case 2:
                        float floatValue = dataOrder == 0 ? byteBuf.getFloat(dataStart) : byteBuf.getFloatLE(dataStart);
                        // float => double: mongodb默认都是double
                        varMap.put(varType, new BigDecimal(Float.toString(floatValue)).doubleValue());
                        break;
                    default:
                        log.error("process varData: dataType[{}] match fail", dataType);
                }
            }
            log.info("process varData: {} => {}", varType, varMap.get(varType));
        }
    }

    /**
     * 处理 NB终端 配置参数
     *
     * @param terminalId
     * @param protocolCode
     * @param byteBuf
     */
    private void processTerminalNBConfigParam(Integer terminalId, String protocolCode, ByteBuf byteBuf) {
        log.info("process terminalNBConfigParam start: {}", ByteBufUtil.hexDump(byteBuf));

        Map<String, Object> paramMap;

        StringBuilder sbAssociatedTerminalMacAddr;
        int householdType, deductionType, chargeType, buyNum;

        switch (protocolCode) {
            // EN1434_9981:WAC330表阀一体-热表:0x56
            case "EN1434_9981":
                // EN1434_9981:WAC520表阀一体-热表:0x58
            case "EN1434_9980":
                paramMap = new HashMap<>(17);
                // 下级终端协议ID
                paramMap.put("associatedTerminalCodeCustomNB", byteBuf.readByte());
                // 下级终端地址
                sbAssociatedTerminalMacAddr = new StringBuilder();
                for (int i = 0; i < 7; i++) {
                    sbAssociatedTerminalMacAddr.append(CodeUtil.byteToHexString(byteBuf.readByte()));
                }
                paramMap.put("associatedTerminalMacAddr", sbAssociatedTerminalMacAddr.toString());
                // 抄表通道：0-TTL；1-485；2-MBUS
                paramMap.put("associatedTerminalSerialNo", byteBuf.readByte());
                // 采暖季开始
                String startDay = CodeUtil.byteToHexString(byteBuf.readByte());
                String startMonth = CodeUtil.byteToHexString(byteBuf.readByte());
                paramMap.put("heatSeasonStart", startMonth + "-" + startDay);
                // 采暖季结束
                String endDay = CodeUtil.byteToHexString(byteBuf.readByte());
                String endMonth = CodeUtil.byteToHexString(byteBuf.readByte());
                paramMap.put("heatSeasonEnd", endMonth + "-" + endDay);
                // 开度上限
                String openDegreeUpperLow = CodeUtil.byteToHexString(byteBuf.readByte());
                String openDegreeUpperHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                paramMap.put("openDegreeUpper", ComUtil.safeInt(openDegreeUpperHigh + openDegreeUpperLow));
                // 开度下限
                String openDegreeLowerLow = CodeUtil.byteToHexString(byteBuf.readByte());
                String openDegreeLowerHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                paramMap.put("openDegreeLower", ComUtil.safeInt(openDegreeLowerHigh + openDegreeLowerLow));
                // 清洗周期
                String cleanCycleLow = CodeUtil.byteToHexString(byteBuf.readByte());
                String cleanCycleHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                paramMap.put("cleanCycle", ComUtil.safeInt(cleanCycleHigh + cleanCycleLow));
                // 调节模式：0-面板控制；1-远程控制开度；2-回水温度控制开度；3-进回水温差控制开度
                int adjustMode = byteBuf.readByte();
                paramMap.put("adjustMode", adjustMode);
                // 是否启用自动调平：0-启用；1-不启用
                paramMap.put("autoAdjust", byteBuf.readByte());
                // 目标调节值（BCD码）50%开度，调节模式不同含义不同，调节模式为00：此处无用；01：表目标开度；02：表目标温度；03：表目标温差
                String adjustValueLow = CodeUtil.byteToHexString(byteBuf.readByte());
                String adjustValueHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                int adjustValue = ComUtil.safeInt(adjustValueHigh + adjustValueLow);
                if (adjustMode == Constant.VALVE_ADJUST_MODE_1) {
                    paramMap.put("adjustValue", adjustValue);
                } else if (adjustMode == Constant.VALVE_ADJUST_MODE_2 || adjustMode == Constant.VALVE_ADJUST_MODE_3) {
                    paramMap.put("adjustValue", adjustValue * 0.01);
                }
                // 调节周期（BCD码）
                String adjustCycleLow = CodeUtil.byteToHexString(byteBuf.readByte());
                String adjustCycleHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                paramMap.put("adjustCycle", ComUtil.safeInt(adjustCycleHigh + adjustCycleLow));
                // 调节死区（BCD码）
                String adjustDeadZoneLow = CodeUtil.byteToHexString(byteBuf.readByte());
                String adjustDeadZoneHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                paramMap.put("adjustDeadZone", ComUtil.safeDouble(ComUtil.safeInt(adjustDeadZoneHigh + adjustDeadZoneLow)) * 0.01);
                // 系数P
                String coefficientPLow = CodeUtil.byteToHexString(byteBuf.readByte());
                String coefficientPHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                paramMap.put("coefficientP", ComUtil.safeDouble(ComUtil.safeInt(coefficientPHigh + coefficientPLow)) * 0.01);
                // 系数I
                String coefficientILow = CodeUtil.byteToHexString(byteBuf.readByte());
                String coefficientIHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                paramMap.put("coefficientI", ComUtil.safeDouble(ComUtil.safeInt(coefficientIHigh + coefficientILow)) * 0.01);
                // 系数D
                String coefficientDLow = CodeUtil.byteToHexString(byteBuf.readByte());
                String coefficientDHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                paramMap.put("coefficientD", ComUtil.safeDouble(ComUtil.safeInt(coefficientDHigh + coefficientDLow)) * 0.01);
                // 调节比例
                String adjustRatioLow = CodeUtil.byteToHexString(byteBuf.readByte());
                String adjustRatioHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                paramMap.put("adjustRatio", ComUtil.safeInt(adjustRatioHigh + adjustRatioLow));

                // 保存终端配置参数
//                utilityService.saveTerminalNBConfigParam4Adjust(terminalId, protocolCode, paramMap);

                log.info("process terminalNBConfigParam: terminalId[{}], protocolCode[{}], configParam[{}]", terminalId, protocolCode, JsonUtil.safeJsonStr(paramMap));
                break;
            // EN1434_0066:WAC550表阀一体-水表-充值水量:0x57
            case "EN1434_0066":
                // EN1434_0062:WAC350表阀一体-水表-充值水量:0x54
            case "EN1434_0062":
                paramMap = new HashMap<>(17);
                // 下级终端协议ID
                paramMap.put("associatedTerminalCodeCustomNB", byteBuf.readByte());
                // 下级终端地址
                sbAssociatedTerminalMacAddr = new StringBuilder();
                for (int i = 0; i < 7; i++) {
                    sbAssociatedTerminalMacAddr.append(CodeUtil.byteToHexString(byteBuf.readByte()));
                }
                paramMap.put("associatedTerminalMacAddr", sbAssociatedTerminalMacAddr.toString());
                // 抄表通道：0-TTL；1-485；2-MBUS
                paramMap.put("associatedTerminalSerialNo", byteBuf.readByte());
                // 阀门清洗间隔720小时，BCD格式
                cleanCycleLow = CodeUtil.byteToHexString(byteBuf.readByte());
                cleanCycleHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                paramMap.put("cleanCycle", ComUtil.safeInt(cleanCycleHigh + cleanCycleLow));
                // 住户类型，00：NULL，01：民用，02：商用。BIN格式
                householdType = byteBuf.readByte();
                paramMap.put("householdType", householdType);
                // 扣费类型，00：NULL，01：水量，02：金额。BIN格式
                deductionType = byteBuf.readByte();
                paramMap.put("deductionType", deductionType);
                // 计费方式，00：NULL。BIN格式
                chargeType = byteBuf.readByte();
                paramMap.put("chargeFactory", chargeType);
                // 购买序列，BIN格式。
                buyNum = byteBuf.readShortLE();
                paramMap.put("buyNum", buyNum);
                // 只采频率，单位分钟，只采集下级终端的频率
                paramMap.put("collectAssociatedTerminalCycle", byteBuf.readShortLE());

                // 保存终端配置参数
//                utilityService.saveTerminalNBConfigParam4LockWAC550(terminalId, protocolCode, paramMap);

                log.info("process terminalNBConfigParam: terminalId[{}], protocolCode[{}], configParam[{}]", terminalId, protocolCode, JsonUtil.safeJsonStr(paramMap));
                break;
            default:
                log.error("process terminalNBConfigParam: protocolCode[{}] match fail", protocolCode);
        }

        log.info("process terminalNBConfigParam end");
    }

    /**
     * 处理 NTR200数据包
     *
     * @param byteBuf
     * @param varMap
     * @return
     */
    private int processNTR200Data(ByteBuf byteBuf, Map<String, Object> varMap) {
        // 采集状态
        int collectStatus = 1;

        try {
            // 节点时间戳
            String v15 = ComUtil.formatDateTime(new Date(ComUtil.safeLong(byteBuf.readIntLE()) * 1000), "yyyy-MM-dd HH:mm:ss");
            varMap.put("15", v15);
            // 温度
            double v04 = ComUtil.safeDouble(byteBuf.readShortLE() * 0.01);
            varMap.put("04", v04);
            // 湿度
            double v03 = ComUtil.safeDouble(byteBuf.readShortLE() * 0.01);
            varMap.put("03", v03);
            // 温度修正
            double v06 = ComUtil.formatScale(byteBuf.readShortLE() * 0.01, 2);
            varMap.put("06", v06);
            // 湿度修正
            double v05 = ComUtil.formatScale(byteBuf.readShortLE() * 0.01, 2);
            varMap.put("05", v05);

            log.info("process temperatureHumidityData: 15[{}],03[{}],04[{}],05[{}],06[{}]", v15, v03, v04, v05, v06);

            collectStatus = 0;
        } catch (Exception e) {
            log.error("process temperatureHumidityData exception", e);
        }
        return collectStatus;
    }

    /**
     * 处理 NBT200-AC数据包
     *
     * @param byteBuf
     * @param varMap
     * @return
     */
    private int processNBT200ACData(ByteBuf byteBuf, Map<String, Object> varMap) {
        // 采集状态
        int collectStatus = 1;

        try {
            // 节点时间戳
            String v15 = ComUtil.formatDateTime(new Date(ComUtil.safeLong(byteBuf.readIntLE()) * 1000), "yyyy-MM-dd HH:mm:ss");
            varMap.put("15", v15);
            // 室内温度
            double v04 = ComUtil.formatScale(byteBuf.readShortLE() * 0.01, 2);
            varMap.put("04", v04);
            // 温度修正值
            double v06 = ComUtil.formatScale(byteBuf.readShortLE() * 0.01, 2);
            varMap.put("06", v06);
            // 设定温度
            double v07 = ComUtil.formatScale(byteBuf.readShortLE() * 0.01, 2);
//            varMap.put("07", v07);
            // 累计工作时间
            int v09 = byteBuf.readIntLE();
//            varMap.put("09", v09);
            // 温度上限
            double v10 = ComUtil.formatScale(byteBuf.readShortLE() * 0.01, 2);
//            varMap.put("10", v10);
            // 温度下限
            double v11 = ComUtil.formatScale(byteBuf.readShortLE() * 0.01, 2);
//            varMap.put("11", v11);
            // 调节死区
            double v13 = ComUtil.formatScale(byteBuf.readShortLE() * 0.01, 2);
//            varMap.put("13", v13);
            // 预留
            byteBuf.skipBytes(6);
            // 状态位
            // DB0：0:温度传感器无故障，1：温度传感器故障
            // DB1：0：温度上限无报警，1：温度上限报警
            // DB2：0：温度下限无报警，1：温度下限报警
            // DB3：0：继电器闭合，1：继电器断开
            // DB4：0：自由控制，1：强制
            short v02 = byteBuf.readShortLE();
            varMap.put("02", v02);

            log.info("process processNBT200ACData: {}", JsonUtil.safeJsonStr(varMap));

            collectStatus = 0;
        } catch (Exception e) {
            log.error("process processNBT200ACData exception", e);
        }
        return collectStatus;
    }
}
